import type { DiscordVoiceState } from '@discordeno/types'
import { ToggleBitfield } from './ToggleBitfield.js'

export const VoiceStateToggle = {
  /** Whether this user is deafened by the server */
  deaf: 1 << 0,
  /** Whether this user is muted by the server */
  mute: 1 << 1,
  /** Whether this user is locally deafened */
  selfDeaf: 1 << 2,
  /** Whether this user is locally muted */
  selfMute: 1 << 3,
  /** Whether this user is streaming using "Go Live" */
  selfStream: 1 << 4,
  /** Whether this user's camera is enabled */
  selfVideo: 1 << 5,
  /** Whether this user is muted by the current user */
  suppress: 1 << 6,
}

export class VoiceStateToggles extends ToggleBitfield {
  constructor(voiceOrTogglesInt: DiscordVoiceState | number) {
    super()

    if (typeof voiceOrTogglesInt === 'number') this.bitfield = voiceOrTogglesInt
    else {
      const voice = voiceOrTogglesInt

      if (voice.deaf) this.add(VoiceStateToggle.deaf)
      if (voice.mute) this.add(VoiceStateToggle.mute)
      if (voice.self_deaf) this.add(VoiceStateToggle.selfDeaf)
      if (voice.self_mute) this.add(VoiceStateToggle.selfMute)
      if (voice.self_stream) this.add(VoiceStateToggle.selfStream)
      if (voice.self_video) this.add(VoiceStateToggle.selfVideo)
      if (voice.suppress) this.add(VoiceStateToggle.suppress)
    }
  }

  /** Whether this user is deafened by the server */
  get deaf(): boolean {
    return this.has('deaf')
  }

  /** Whether this user is muted by the server */
  get mute(): boolean {
    return this.has('mute')
  }

  /** Whether this user is locally deafened */
  get selfDeaf(): boolean {
    return this.has('selfDeaf')
  }

  /** Whether this user is locally muted */
  get selfMute(): boolean {
    return this.has('selfMute')
  }

  /** Whether this user is streaming using "Go Live" */
  get selfStream(): boolean {
    return this.has('selfStream')
  }

  /** Whether this user's camera is enabled */
  get selfVideo(): boolean {
    return this.has('selfVideo')
  }

  /** Whether this user is muted by the current user */
  get suppress(): boolean {
    return this.has('suppress')
  }

  /** Checks whether or not the permissions exist in this */
  has(permissions: VoiceStateToggleKeys | VoiceStateToggleKeys[]): boolean {
    if (!Array.isArray(permissions)) return super.contains(VoiceStateToggle[permissions])

    return super.contains(permissions.reduce((a, b) => (a |= VoiceStateToggle[b]), 0))
  }

  /** Lists all the toggles for the role and whether or not each is true or false. */
  list(): Record<VoiceStateToggleKeys, boolean> {
    const json: Record<string, boolean> = {}
    for (const [key, value] of Object.entries(VoiceStateToggle)) {
      json[key] = super.contains(value)
    }

    return json as Record<VoiceStateToggleKeys, boolean>
  }
}

export type VoiceStateToggleKeys = keyof typeof VoiceStateToggle
